package com.cn.server.sever;

import com.cn.common.core.codc.RequestDecoder;
import com.cn.common.core.codc.ResponseEncoder;
import com.cn.server.module.httpHandler.TextWebSocketFrameHandler;
import com.cn.server.module.player.service.PlayerService;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.stream.ChunkedWriteHandler;
import io.netty.handler.timeout.IdleStateHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.net.InetSocketAddress;

/**
 * netty服务端入门
 */
@Component
public class Server {
    @Autowired
    private PlayerService playerService;

    /**
     * 启动
     */
    @PostConstruct
    public void start() {
        System.out.println(Thread.currentThread().getName());
        // 服务类
        ServerBootstrap b = new ServerBootstrap();
        ServerBootstrap b2 = new ServerBootstrap();

        // 创建boss和worker
        //一个eventLoopGroup中有很多eventLoop，相当于一个线程，一个channel整个生命周期内
        // 和一个eventLoop绑定，而一个线程可以和多个channel绑定。即一个线程服务多个channel(顾客)
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        EventLoopGroup serviceGroup = new NioEventLoopGroup();
        //createServer(b, bossGroup, workerGroup, serviceGroup, 10103);
        createServer1(b, bossGroup, workerGroup, serviceGroup,10102);
        createServer2(b2, bossGroup, workerGroup, serviceGroup,10103);

    }

    private void createServer(ServerBootstrap b, EventLoopGroup bossGroup, EventLoopGroup workerGroup, final EventLoopGroup serviceGroup, int port) {
        try {
            // 设置循环线程组事例
            b.group(bossGroup, workerGroup);

            // 设置channel工厂
            b.channel(NioServerSocketChannel.class);
            b.childHandler(new ChannelInitializerImpl(serviceGroup));
            //设置监听端口
            b.localAddress(port);
            //设置TCP参数
            // 有数据立即发送,如果发送大数据时，设置为 false
            b.option(ChannelOption.TCP_NODELAY, true);
            // 保持连接
            b.childOption(ChannelOption.SO_KEEPALIVE, true);
            // 链接缓冲池队列大小
            b.option(ChannelOption.SO_BACKLOG, 2048);
            //启用对象池的byteBuf,设置必须在bind前面
            b.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
            // 绑定端口
            ChannelFuture fu = b.bind().sync();
            fu.addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture cf) throws Exception {
                    if(cf.isSuccess()){

                    System.out.println("server====starting");
                    }else{
                        System.out.println("server====failed");
                        cf.cause().printStackTrace();
                    }
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void createServer1(ServerBootstrap b, EventLoopGroup bossGroup, EventLoopGroup workerGroup, final EventLoopGroup serviceGroup, int port) {
        try {
            // 设置循环线程组事例
            b.group(bossGroup, workerGroup);

            // 设置channel工厂
            b.channel(NioServerSocketChannel.class);
            //设置监听端口
            b.localAddress(port);
            // 设置管道，当有连接时，调用下面的方法
            b.childHandler(new ChannelInitializer<SocketChannel>() {
                @Override
                public void initChannel(SocketChannel ch) throws Exception {
                    ChannelPipeline pipeline = ch.pipeline();
                    //======================== 自定义的协议 =====================////
                    //encoer按照ChannelOutboundHandler，逆序执行
                    //decoder按照ChannelIntboundHandler，按照顺序执行
                    IdleStateHandler idleStateHandler = new IdleStateHandler(10, 10, 20);
                    pipeline.addLast(idleStateHandler);
                    pipeline.addLast(new RequestDecoder());
                    pipeline.addLast(new ResponseEncoder());
                    pipeline.addLast(serviceGroup, new ServerHandler(playerService));

                }
            });

            //设置TCP参数
            // 链接缓冲池队列大小
            b.option(ChannelOption.SO_BACKLOG, 2048);
            //启用对象池的byteBuf,设置必须在bind前面
            b.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);

            // 绑定端口
            ChannelFuture fu = b.bind().sync();
            fu.addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture cf) throws Exception {
                    if(cf.isSuccess()){

                        System.out.println("server====starting");
                    }else{
                        System.out.println("server====failed");
                        cf.cause().printStackTrace();
                    }
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void createServer2(ServerBootstrap b, EventLoopGroup bossGroup, EventLoopGroup workerGroup, final EventLoopGroup serviceGroup, int port) {
        try {
            // 设置循环线程组事例
            b.group(bossGroup, workerGroup);

            // 设置channel工厂
            b.channel(NioServerSocketChannel.class);
            //设置监听端口
            b.localAddress(port);
            // 设置管道，当有连接时，调用下面的方法
            b.childHandler(new ChannelInitializer<SocketChannel>() {

                @Override
                public void initChannel(SocketChannel ch) throws Exception {
                    ChannelPipeline pipeline = ch.pipeline();
                    //======================= websocket =======================///
                    IdleStateHandler idleStateHandler = new IdleStateHandler(50, 50, 100);
                    pipeline.addLast(idleStateHandler);
                    pipeline.addLast(new HttpServerCodec());
                    //以块的方式来写的处理器
                    pipeline.addLast(new ChunkedWriteHandler());
                    //netty是基于分段请求的，HttpObjectAggreator的作用是将
                    //请求分段再聚合，参数是聚合字节的最大长度
                    pipeline.addLast(new HttpObjectAggregator(8192));
                    //创建一个http请求Handler
                    pipeline.addLast(new WebSocketServerProtocolHandler("/ws"));
                    //帧的传输类型，这里使用的是处理文本类型的Handler
                    System.out.println("pipeline:" + Thread.currentThread().getName());
                    pipeline.addLast(serviceGroup, new ServerHandler(playerService));

                }
            });
            //设置TCP参数
            // 链接缓冲池队列大小
            b.option(ChannelOption.SO_BACKLOG, 2048);
            //启用对象池的byteBuf,设置必须在bind前面
            b.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
            // 绑定端口
            ChannelFuture fu = b.bind().sync();
            fu.addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture cf) throws Exception {
                    if(cf.isSuccess()){
                        System.out.println("server====starting");
                    }else{
                        System.out.println("server====failed");
                        cf.cause().printStackTrace();
                    }
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
